package com.moliku.insurance.process.service.impl;


import cn.hutool.core.util.CharsetUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.google.common.base.Joiner;
import com.moliku.insurance.common.constant.CompanyEnum;
import com.moliku.insurance.common.constant.InsureStatusEnum;
import com.moliku.insurance.common.constant.OrderEnum;
import com.moliku.insurance.common.constant.PolicyConfigKeyEnum;
import com.moliku.insurance.common.response.CommonInsureResult;
import com.moliku.insurance.common.util.ByteUtils;
import com.moliku.insurance.model.dto.CancelInsureDTO;
import com.moliku.insurance.model.dto.DownloadInsureDTO;
import com.moliku.insurance.model.dto.insure.InsureDTO;
import com.moliku.insurance.model.entity.Order;
import com.moliku.insurance.model.entity.OrderDetail;
import com.moliku.insurance.model.entity.YaTai.*;
import com.moliku.insurance.process.mapper.BaseOrderMapper;
import com.moliku.insurance.process.service.ConfigService;
import com.moliku.insurance.process.strategy.PolicyStrategy;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;
import java.io.UnsupportedEncodingException;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;


/**
 * 亚太财险
 *
 * @author Mr.Liu
 * @since 2021/2/25
 */
@Slf4j
@Service("ApiInsService")
@AllArgsConstructor
public class ApiInsServiceImpl implements PolicyStrategy {
    /**
     * TODO 授权信息  暂时写死
     */
    final String appId = "0A688C599566CCB2ED0885DC83033954";
    final String appSecret = "3A1B998D3180F9D82FAF0E3B661CDF00";
    final String agrtCode = "011F8000010000";
    final String dataSource = "O-BYW";
    final String KEY = "accessToken";
    final long EXPIRE = 23;
    final String CODE = "0000";

    private static final String URL_TB_YT = "http://ncar-test12.apiins.com/make-order";
    private static final String URL_TUI_YT = "http://ncar-test12.apiins.com/cancel-insurance";
    private static final String URL_DOWN_YT = "http://ncar-test12.apiins.com/query-epolicy";

    private final RestTemplate restTemplate = new RestTemplate();
    private final RedisTemplate<String, String> redisTemplate;

    @Resource
    private final BaseOrderMapper baseOrderMapper;
    @Resource
    private final ConfigService configService;


    @Override
    public CommonInsureResult submitPolicy(InsureDTO request) {

        try {
            String json = getParam(request);

            HashMap<String, String> urlMap = new HashMap<>(2);
            String accessToken = getAccessToken();
            urlMap.put("appId", configService.getConfigValue(CompanyEnum.APIINS,"appId"));
            urlMap.put("token", accessToken);
            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(MediaType.parseMediaType("application/json;charset=UTF-8"));
            headers.add("Accept", MediaType.APPLICATION_JSON.toString());
            HttpEntity<String> httpEntity = new HttpEntity<>(json,headers);
            log.info("封装数据:" + json);
            String urlTb= configService.getConfigValue(CompanyEnum.APIINS, PolicyConfigKeyEnum.SUBMIT_POLICY_URL);
            String url = splicUrl(urlTb, urlMap);
            log.info("url:" + url);
            ResponseEntity<String> forEntity = restTemplate.postForEntity(url, httpEntity, String.class);
            String responseMessage = "";
            if (StringUtils.isNotBlank(forEntity.getBody())) {
                //解密url编码
                responseMessage = java.net.URLDecoder.decode(forEntity.getBody(), CharsetUtil.UTF_8);
            }
            //将返回结果转json
            JSONObject jsonObject = JSONObject.parseObject(responseMessage);
            String code = jsonObject.getString("code");
            String message = jsonObject.getString("message");

            //修改订单详情表中投保时保险公司返回数据
            OrderDetail orderDetail = new OrderDetail();
            orderDetail.setOrderId(request.getLocalOrderId());
            orderDetail.setInsureRsp(responseMessage);
            baseOrderMapper.updateOrderDeatailByOrderId(orderDetail);

            if (CODE.equals(code)) {
                log.info("亚太投保成功!{" + responseMessage + "}");
                jsonObject = JSONObject.parseObject(jsonObject.getString("data"));
                jsonObject = JSONObject.parseObject(jsonObject.getString("createOrderResp"));
                String policyNo = jsonObject.getString("policyNo");
                String orderExt = jsonObject.getString("orderExt");
                String orderCode = jsonObject.getString("orderCode");
                Order order = new Order();
                order.setId(request.getLocalOrderId());
                order.setPolicyNo(policyNo);
                order.setStatus(OrderEnum.CLOSED_NO_REFUND.getValue());
                order.setOrderExt(orderExt);
                order.setOrderCode(orderCode);
                baseOrderMapper.updateById(order);
                return CommonInsureResult.submitPolicySuccess(policyNo);
            } else {
                log.error("亚太投保失败!{投保信息校验不通过," + message + "}");
                return CommonInsureResult.submitPolicyFail(message);
            }

        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return CommonInsureResult.submitPolicyFail();
    }


    @Override
    public CommonInsureResult cancelPolicy(CancelInsureDTO request) {

        Order order = baseOrderMapper.selectByPolicyNo(request.getPolicyNo());
        if (order == null) {
            return CommonInsureResult.cancelPolicyFail(InsureStatusEnum.CANCEL_INSURE_FAIL_5202);

        }
        String json = getTui(request, order);

        HashMap<String, String> urlMap = new HashMap<>(3);

        String accessToken = getAccessToken();
        urlMap.put("appId", configService.getConfigValue(CompanyEnum.APIINS,"appId"));
        urlMap.put("token", accessToken);
        urlMap.put("accessToken", accessToken);
        HttpEntity<String> httpEntity = new HttpEntity<>(json);

        String urlTui =configService.getConfigValue(CompanyEnum.APIINS, PolicyConfigKeyEnum.CANCEL_POLICY_URL);
        ResponseEntity<String> forEntity = restTemplate.postForEntity(splicUrl(urlTui, urlMap), httpEntity, String.class);
        //将返回信息转成json
        JSONObject jsonObject = JSONObject.parseObject(forEntity.getBody());
        String code = jsonObject.getString("code");
        String message = jsonObject.getString("message");


        //修改订单详情表中退保时保险公司返回数据
        OrderDetail orderDetail = new OrderDetail();
        orderDetail.setOrderId(order.getId());
        orderDetail.setCancelPolicyRsp(jsonObject.toJSONString());
        baseOrderMapper.updateOrderDeatailByOrderId(orderDetail);

        if (CODE.equals(code)) {
            log.info("亚太退保成功!{}", forEntity.getBody());
            order.setStatus(OrderEnum.CANCEL.getValue());
            baseOrderMapper.updateById(order);
            return CommonInsureResult.cancelPolicySuccess();
        } else {
            log.error("亚太退保失败!{}", message);
            return CommonInsureResult.cancelPolicyFail(message);
        }

    }

    @Override
    public CommonInsureResult downloadPolicy(DownloadInsureDTO downloadInsure) {

        Order order = baseOrderMapper.selectByPolicyNo(downloadInsure.getPolicyNo());
        if (order == null) {
            return CommonInsureResult.downloadPolicyFail(InsureStatusEnum.DOWNLOAD_INSURE_FAIL);
        }
        OrderDetail orderDetail = baseOrderMapper.selectDeatailByOrderId(order.getId());
        JSONObject jsonObject = JSONObject.parseObject(orderDetail.getData());
        JSONArray jsonArray = jsonObject.getJSONArray("insureds");
        jsonObject = jsonArray.getJSONObject(0);
        String docNo = jsonObject.getString("cardNo");
        String accessToken = getAccessToken();
        Map<String, String> map = new HashMap<>(2);
        map.put("policyNo", downloadInsure.getPolicyNo());
        map.put("insuredID", docNo);
        HashMap<String, String> urlMap = new HashMap<>(2);
        urlMap.put("appId", configService.getConfigValue(CompanyEnum.APIINS,"appId"));
        urlMap.put("token", accessToken);


        HttpEntity<Map<String, String>> httpEntity = new HttpEntity<>(map);
        String urlDown =configService.getConfigValue(CompanyEnum.APIINS,PolicyConfigKeyEnum.DOWNLOAD_POLICY_URL);
        ResponseEntity<String> forEntity = restTemplate.postForEntity(splicUrl(urlDown, urlMap), httpEntity, String.class);
        //将返回信息转成json
        jsonObject = JSONObject.parseObject(forEntity.getBody());
        String code = jsonObject.getString("code");
        String errorMsg = jsonObject.getString("errorMsg");

        if (CODE.equals(code)) {
            String imgUrl = jsonObject.getString("imgURL");
            byte[] bytes = ByteUtils.urlToByte(imgUrl);
            log.info("下载电子保单成功!{}", imgUrl);
            return CommonInsureResult.downloadPolicySuccess(bytes);
        }
        log.error("下载电子保单失败!{}", forEntity.getBody());
        return CommonInsureResult.downloadPolicyFail(errorMsg);
    }


    /**
     * 投保
     */
    public String getParam(InsureDTO request) {
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("agrtCode", configService.getConfigValue(CompanyEnum.APIINS,"agrtCode"));
        jsonObject.put("requestTime", LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
        jsonObject.put("dataSource", configService.getConfigValue(CompanyEnum.APIINS,"dataSource"));
        jsonObject.put("outBusinessCode", request.getOrder().getSerialNumber());
        jsonObject.put("interfaceCode", "CreateOrder");

        OrderAndBatchFlag orderAndBatchFlag = new OrderAndBatchFlag();
        List<OrderList> orderLists = new ArrayList<>();
        CreateOrderReq createOrderReq =new CreateOrderReq();
        OrderList orderList = new OrderList();

        //基础信息
        BaseInfo baseInfo = new BaseInfo();
        baseInfo.setStartDate(request.getOrder().getStartTime());
        baseInfo.setEndDate(request.getOrder().getEndTime());
        baseInfo.setUwCount("1");


        //投保人列表
        List<Customer> customerList = new ArrayList<>();

        Customer customer = new Customer();
        customer.setCustomerType("1");
        customer.setCustomerName(request.getPolicyHolder().getcName());
        customer.setCustomerSameInd("1");
        customer.setDocType(getDocType(request.getPolicyHolder().getCardType()));
        customer.setDocNo(request.getPolicyHolder().getCardNo());

        String sex = request.getPolicyHolder().getSex();
        sex = "0".equals(sex) ? "02" : "01";
        customer.setSex(sex);
        customer.setBirthDate(request.getPolicyHolder().getBirthDay());
        customer.setPhoneNo(request.getPolicyHolder().getMobile());
        customer.setEmail(request.getPolicyHolder().getEmail());
        customer.setCustomerFlag("1");
        customerList.add(customer);


        //标的主信息
        List<ItemAcci> itemAcciList = new ArrayList<>();
        ItemAcci itemAcci = new ItemAcci();
        itemAcci.setQuantity(1);
        itemAcci.setNominativeInd("1");


        //人员清单
        List<AcciInsuredList> acciInsuredList = new ArrayList<>();
        for (int i = 0; i < request.getInsureds().size(); i++) {
            AcciInsuredList acciInsured = new AcciInsuredList();
            acciInsured.setCustomerName(request.getInsureds().get(i).getCName());
            acciInsured.setDocType(getDocType(request.getInsureds().get(i).getCardType()));
            acciInsured.setDocNo(request.getInsureds().get(i).getCardNo());
            acciInsured.setBirthDate(request.getInsureds().get(i).getBirthDay());
            acciInsured.setCustomerFlag("2");
            sex = request.getInsureds().get(0).getSex();
            sex = "0".equals(sex) ? "02" : "01";
            acciInsured.setSex(sex);
            acciInsured.setAppliRelation("01");
            acciInsured.setOccupationCode("0000000");
            acciInsuredList.add(acciInsured);
        }
        itemAcci.setAcciInsuredList(acciInsuredList);
        itemAcciList.add(itemAcci);


        orderList.setBaseInfo(baseInfo);
        orderList.setCustomerList(customerList);
        orderList.setItemAcciList(itemAcciList);
        orderLists.add(orderList);

        createOrderReq.setOrderList(orderLists);

        orderAndBatchFlag.setCreateOrderReq(createOrderReq);

        jsonObject.put("data", orderAndBatchFlag);
        String json = JSONObject.toJSONString(jsonObject);
        System.out.println(json);
        return json;
    }


    /**
     * 退保
     */
    public String getTui(CancelInsureDTO request, Order order) {

        JSONObject jsonObject =new JSONObject();
        //退保时的接口标识
        jsonObject.put("interfaceCode","CancelInsurance");
        jsonObject.put("requestTime",LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
        jsonObject.put("dataSource",configService.getConfigValue(CompanyEnum.APIINS,"dataSource"));
        jsonObject.put("agrtCode",configService.getConfigValue(CompanyEnum.APIINS,"agrtCode"));
        jsonObject.put("outBusinessCode",order.getSerialNo());

        CancelInsuranceReq cancelInsuranceReq = new CancelInsuranceReq();
        cancelInsuranceReq.setOrderCode(order.getOrderCode());
        cancelInsuranceReq.setOrderExt(order.getOrderExt());
        cancelInsuranceReq.setPolicyNo(request.getPolicyNo());
        cancelInsuranceReq.setValidDate(LocalDateTime.now().plusHours(1).format(DateTimeFormatter.ofPattern("yyyy-MM-dd hh:mm:ss")));

        PolicyCancellation policyCancellation=new PolicyCancellation();
        policyCancellation.setCancelInsuranceReq(cancelInsuranceReq);

        jsonObject.put("data",policyCancellation);

        return JSONObject.toJSONString(jsonObject);
    }


    /**
     * 获取accessToken
     */
    public String getAccessToken() {
        String accessToken = redisTemplate.boundValueOps(KEY).get();
        if (StringUtils.isNotBlank(accessToken)) {
            log.info("命中redis");
            return accessToken;
        }
        String url = "http://ncar-test12.apiins.com/oauth/token/getAccessToken";
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.parseMediaType("application/json;charset=UTF-8"));
        JSONObject data = new JSONObject();
        data.put("appId", configService.getConfigValue(CompanyEnum.APIINS,"appId"));
        data.put("appSecret", configService.getConfigValue(CompanyEnum.APIINS,"appSecret"));
        HttpEntity<JSONObject> httpEntity = new HttpEntity<>(data, headers);
        ResponseEntity<String> entity = restTemplate.postForEntity(url, httpEntity, String.class);
        data = JSONObject.parseObject(entity.getBody());
        String token = data.getString("accessToken");

        //添加缓存
        redisTemplate.boundValueOps(KEY).set(token);
        //添加失效时间
        redisTemplate.boundValueOps(KEY).expire(EXPIRE, TimeUnit.HOURS);
        return token;
    }

    /**
     * 清理AccessToken
     */
    public void clearAccessToken(String accessToken) {
        String url = "http://ncar-test12.apiins.com/oauth/token/clearAccessToken";
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.parseMediaType("application/json;charset=UTF-8"));
        headers.add("Accept", MediaType.APPLICATION_JSON.toString());
        JSONObject data = new JSONObject();
        data.put("appId", configService.getConfigValue(CompanyEnum.APIINS,"appId"));
        data.put("accessToken", accessToken);
        HttpEntity<JSONObject> httpEntity = new HttpEntity<>(data, headers);
        ResponseEntity<JSONObject> responseEntity = restTemplate.postForEntity(url, httpEntity, JSONObject.class);

        //清除缓存
        redisTemplate.delete(KEY);
        log.info("清理AccessToken:{}", responseEntity.toString());
    }

    public String splicUrl(String url, Map<String, String> source) {
        if (source.size() < 1) {
            return url;
        }
        return url + "?" + asUrlParams(source);
    }

    public String asUrlParams(Map<String, String> source) {
        return Joiner.on("&")
                // 用指定符号代替空值,key 或者value 为null都会被替换
                .useForNull("")
                .withKeyValueSeparator("=")
                .join(source);
    }

    private static String getDocType(String docType) {
        switch (docType) {
            case "1":
                return "01";
            case "2":
                return "02";
            case "3":
                return "03";
            case "4":
                return "04";
            case "5":
                return "05";
            case "6":
                return "06";
            case "12":
                return "07";
            case "53":
                return "11";
            case "72":
                return "1";
            case "70":
                return "3";
            default:
                break;
        }
        return null;
    }


}
